﻿#include "ssMySqlPy.h"
#include "log/ssLogThread.h"
#include "string/ssStrfunc.h"


namespace StarSeeker
{

ssMySqlPyQuery::ssMySqlPyQuery()
: m_result(NULL), m_fieldCount(0), m_rowCount(0), m_currentRow(NULL)
{

}

ssMySqlPyQuery::ssMySqlPyQuery(ssMySqlPyQuery &rQuery)
: m_result(NULL), m_fieldCount(0), m_rowCount(0), m_currentRow(NULL)
{
	*this = rQuery;
}

ssMySqlPyQuery::~ssMySqlPyQuery()
{
	freeRes();
}

ssMySqlPyQuery& ssMySqlPyQuery::operator=(ssMySqlPyQuery &rQuery)
{
	if (this == &rQuery)
	{
		return *this;
	}

	freeRes();

	m_result = rQuery.m_result;
	m_fieldCount = 0;
	m_rowCount = 0;
	m_currentRow = NULL;

	if (m_result != NULL)
	{
		mysql_data_seek(m_result, 0);
		m_fieldCount = mysql_num_fields(m_result);
		m_rowCount = static_cast<int>(mysql_num_rows(m_result));
		m_currentRow = mysql_fetch_row(m_result);
	}

	rQuery.m_result = NULL;
	rQuery.m_fieldCount = 0;
	rQuery.m_rowCount = 0;
	rQuery.m_currentRow = NULL;

	return *this;
}

void ssMySqlPyQuery::setRes(MYSQL_RES *res)
{
	this->freeRes();
	m_result = res;
	if (m_result != NULL)
	{
		m_fieldCount = mysql_num_fields(m_result);
		m_rowCount = static_cast<int>(mysql_num_rows(m_result));
		
		mysql_data_seek(m_result, 0);
		m_currentRow = mysql_fetch_row(m_result);
	}
}

void ssMySqlPyQuery::freeRes()
{
	if (m_result != NULL)
	{
		mysql_free_result(m_result);
		m_result = NULL;
		m_rowCount = 0;
		m_fieldCount = 0;
		m_currentRow = NULL;
	}
}

int ssMySqlPyQuery::getFieldCount()
{
	return m_fieldCount;
}

int ssMySqlPyQuery::getRowCount()
{
	return m_rowCount;
}

int ssMySqlPyQuery::seekRow(int index)
{
	if (m_rowCount <= 0 || index < 0 || index >= m_rowCount)
	{
		return 0;		
	}

	mysql_data_seek(m_result, index);
	m_currentRow = mysql_fetch_row(m_result);

	return index;
}

void ssMySqlPyQuery::nextRow()
{
	if (m_result != NULL)
	{
		m_currentRow = mysql_fetch_row(m_result);
	}
}


bool ssMySqlPyQuery::eof()
{
	return m_currentRow == NULL;
}

const char* ssMySqlPyQuery::getStringValue(int fieldIndex, const char *strNull)
{
	if (m_result == NULL || m_currentRow == NULL || m_fieldCount <= 0 || fieldIndex < 0 || fieldIndex >= m_fieldCount)
	{
		return strNull;
	}

	return m_currentRow[fieldIndex];
}

const char* ssMySqlPyQuery::getStringValue(const char *fieldName, const char *strNull)
{
	if (m_result == NULL || m_currentRow == NULL || fieldName == NULL)
	{
		return strNull;
	}

	int fieldIndx = this->getFieldIndex(fieldName);

	return this->getStringValue(fieldIndx, strNull);
}

int ssMySqlPyQuery::getIntValue(int fieldIndex, const int intNull)
{
	if (m_result == NULL || m_currentRow == NULL || m_fieldCount <= 0 || fieldIndex < 0 || fieldIndex >= m_fieldCount || m_currentRow[fieldIndex] == NULL)
	{
		return intNull;
	}

	return atoi(m_currentRow[fieldIndex]);
}


int ssMySqlPyQuery::getIntValue(const char *fieldName, const int intNull)
{
	if (m_result == NULL || m_currentRow == NULL || fieldName == NULL)
	{
		return intNull;
	}

	int fieldIndx = this->getFieldIndex(fieldName);

	return this->getIntValue(fieldIndx, intNull);
}

double ssMySqlPyQuery::getDoubleValue(int fieldIndex, const int intNull)
{
	if (m_result == NULL || m_currentRow == NULL || m_fieldCount <= 0 || fieldIndex < 0 || fieldIndex >= m_fieldCount || m_currentRow[fieldIndex] == NULL)
	{
		return intNull;
	}

	return atof(m_currentRow[fieldIndex]);
}

double ssMySqlPyQuery::getDoubleValue(const char *fieldName, const int intNull)
{
	if (m_result == NULL || m_currentRow == NULL || fieldName == NULL)
	{
		return intNull;
	}

	int fieldIndx = this->getFieldIndex(fieldName);

	return this->getDoubleValue(fieldIndx, intNull);
}


const char* ssMySqlPyQuery::getOneCell(const char *strNull)
{
	if (m_result == NULL || m_rowCount <= 0 || m_fieldCount <= 0)
	{
		return strNull;
	}

	this->seekRow(0);

	return this->getStringValue(0);
}

int ssMySqlPyQuery::getFieldIndex(const char *fieldName)
{
	if (m_result == NULL || m_fieldCount <= 0 || fieldName == NULL)
	{
		return -1;
	}

	mysql_field_seek(m_result, 0);
	for (int i = 0; i < m_fieldCount; ++i)
	{
		MYSQL_FIELD *field = mysql_fetch_field(m_result);
		if (field != NULL && strcasecmp(field->name, fieldName) == 0)
		{
			return i;
		}
	}

	return -1;
}

enum_field_types ssMySqlPyQuery::getFieldType(const char *fieldName)
{
	if (m_result == NULL || m_fieldCount <= 0 || fieldName == NULL)
	{
		return MYSQL_TYPE_NULL;
	}

	mysql_field_seek(m_result, 0);
	for (int i = 0; i < m_fieldCount; ++i)
	{
		MYSQL_FIELD *field = mysql_fetch_field(m_result);
		if (field != NULL && strcasecmp(field->name, fieldName) == 0)
		{
			return field->type;
		}
	}

	return MYSQL_TYPE_NULL;
}

enum_field_types ssMySqlPyQuery::getFieldType(int fieldIndex)
{
	if (m_result == NULL || m_fieldCount <= 0 || fieldIndex >= m_fieldCount || fieldIndex < 0)
	{
		return MYSQL_TYPE_NULL;
	}

	mysql_field_seek(m_result, 0);
	for (int i = 0; i < m_fieldCount; ++i)
	{
		MYSQL_FIELD *field = mysql_fetch_field(m_result);
		if (field != NULL && i == fieldIndex)
		{
			return field->type;
		}
	}
	return MYSQL_TYPE_NULL;
}

bool ssMySqlPyQuery::isFieldTypeString(const char *fieldName)
{
	enum_field_types type = getFieldType(fieldName);
	if(type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_STRING)
	{
		return true;
	}
	return false;
}

bool ssMySqlPyQuery::isFieldTypeString(int fieldIndex)
{
	enum_field_types type = getFieldType(fieldIndex);
	if(type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_VAR_STRING || type == MYSQL_TYPE_STRING)
	{
		return true;
	}
	return false;
}

const char* ssMySqlPyQuery::getFieldName(int fieldIndex, const char *strNull)
{
	if (m_result == NULL || m_fieldCount <= 0)
	{
		return strNull;
	}

	if (fieldIndex < 0 || fieldIndex >= m_fieldCount)
	{
		return strNull;
	}

	mysql_field_seek(m_result, fieldIndex);
	MYSQL_FIELD *field = mysql_fetch_field(m_result);
	if (field != NULL)
	{
		return field->name;
	}
	else
	{
		return strNull;
	}
}

ssMySqlPy::ssMySqlPy()
: m_connection(NULL), m_port(0)
{

}

ssMySqlPy::~ssMySqlPy()
{
	clearResult();
	this->close();
}

bool ssMySqlPy::open(const std::string &host, const std::string &user, const std::string &passwd, const std::string &db, unsigned int port)
{
	MYSQL *pConnection = mysql_init(NULL);
	if (pConnection == NULL)
	{
		return false;
	}

	if (mysql_real_connect(pConnection, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, NULL, 0) == NULL)
	{
		return false;
	}

	if (mysql_set_character_set(pConnection, "utf8") != 0)
	{
		mysql_close(pConnection);
		return false;
	}
	 
	this->close();

	m_connection = pConnection;

	m_host = host;
	m_user = user;
	m_passwd = passwd;
	m_db = db;
	m_port = port;

	return true;
}

void ssMySqlPy::close()
{
	if (m_connection != NULL)
	{
		mysql_close(m_connection);
		m_connection = NULL;
	}
}

bool ssMySqlPy::reopen()
{
	return this->open(m_host, m_user, m_passwd, m_db, m_port);
}

ssMySqlPyQuery& ssMySqlPy::query(const char *sql)
{
	int error = this->excute(sql);
	if (error == 0)
	{
		m_query.setRes(mysql_store_result(m_connection));
	}
	else
	{
		m_query.setRes(NULL);
	}

	return m_query;
}

int ssMySqlPy::excute(const char *sql)
{
	if (m_connection == NULL || sql == NULL)
	{
		SS_LOG->ErrorEx("MySqlDB::excute return with m_connection = %p, sql = %p", m_connection, sql);
		return DB_QUERY_CONNECT_NULL;
	}

	if (mysql_query(m_connection, sql) != 0)
	{
		int error = mysql_errno(m_connection);
		if (error == 2014 || error == 2006 || error == 2013)
		{
			SS_LOG->ErrorEx("mysql_real_query failed with error = %d, sql = %s, try reopen", error, sql);
			this->reopen();

			if (mysql_query(m_connection, sql) != 0)
			{
				SS_LOG->Error("mysql_real_query still failed after reopen");
				return DB_QUERY_CONNECT_NULL;
			}
			else
			{
				SS_LOG->Error("mysql_real_query succeed after reopen");
				return DB_QUERY_OK;
			}
		}
		else
		{
			SS_LOG->ErrorEx("mysql_real_query failed with error = %d, sql = %s", error, sql);
			return DB_QUERY_ERROR;
		}
	}
		
	return DB_QUERY_OK;
}

int ssMySqlPy::lastInsertId()
{
	return static_cast<int>(mysql_insert_id(m_connection));
}

void ssMySqlPy::clearResult()
{
	if (m_connection)
	{
		while (0 == mysql_next_result(m_connection))
		{
			MYSQL_RES* res = mysql_store_result(m_connection);
			mysql_free_result(res);
		}
	}
}

const char* ssMySqlPy::getError()
{
	if (!m_connection)
		return 0;

	return mysql_error(m_connection);
}

}
